//SPDX-FileCopyrightText: Copyright 2025-2025 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package user_api_serv

import (
	"context"
	"regexp"
	"strings"
	"time"

	"gitcode.com/eteam/api-server/api_common"
	"gitcode.com/eteam/api-server/dao"
	"gitcode.com/eteam/api-server/dao/user_dao"
	"gitcode.com/eteam/proto-gen-go.git/user_api"
	"github.com/dchest/uniuri"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

func (apiImpl *UserApiImpl) Login(ctx context.Context, req *user_api.LoginRequest) (*user_api.LoginResponse, error) {
	emptyInfo := &user_api.UserInfo{
		BasicInfo: &user_api.BasicUserInfo{},
	}

	userInfoItem, err := user_dao.UserInfoDao.GetByName(ctx, req.UserName)
	if err != nil {
		return &user_api.LoginResponse{
			Code:     user_api.LoginResponse_CODE_WRONG_USERNAME,
			ErrMsg:   "用户不存在",
			UserInfo: emptyInfo,
		}, nil
	}
	err = user_dao.UserPasswdDao.Auth(ctx, userInfoItem.UserId, req.Passwd)
	if err != nil {
		return &user_api.LoginResponse{
			Code:     user_api.LoginResponse_CODE_WRONG_PASSWD,
			ErrMsg:   "密码错误",
			UserInfo: emptyInfo,
		}, nil
	}
	if userInfoItem.UserState == user_api.USER_STATE_USER_STATE_FORBIDDEN {
		return &user_api.LoginResponse{
			Code:     user_api.LoginResponse_CODE_USER_FORBIDDEN,
			ErrMsg:   "用户被冻结",
			UserInfo: emptyInfo,
		}, nil
	}
	//创建会话
	sessionId := uniuri.NewLen(32) + strings.ReplaceAll(uuid.NewString(), "-", "")

	dao.CacheDao.SetSession(ctx, &dao.SessionDbItem{
		SessionId:   sessionId,
		UserId:      userInfoItem.UserId,
		UserName:    userInfoItem.UserName,
		DisplayName: userInfoItem.BasicInfo.DisplayName,
		LogoUri:     userInfoItem.BasicInfo.LogoUri,
	})

	return &user_api.LoginResponse{
		Code:      user_api.LoginResponse_CODE_OK,
		SessionId: sessionId,
		UserInfo:  userInfoItem.ToUserInfo(),
	}, nil
}

func (apiImpl *UserApiImpl) Logout(ctx context.Context, req *user_api.LogoutRequest) (*user_api.LogoutResponse, error) {
	dao.CacheDao.RemoveSession(ctx, req.SessionId)

	return &user_api.LogoutResponse{
		Code: user_api.LogoutResponse_CODE_OK,
	}, nil
}

func (apiImpl *UserApiImpl) UpdateBasic(ctx context.Context, req *user_api.UpdateBasicRequest) (*user_api.UpdateBasicResponse, error) {
	sessItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_api.UpdateBasicResponse{
			Code:   user_api.UpdateBasicResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err := user_dao.UserInfoDao.UpdateBasicInfo(sessCtx, sessItem.UserId, &user_dao.BasicUserInfoDbItem{
			DisplayName: req.BasicInfo.DisplayName,
			LogoUri:     req.BasicInfo.LogoUri,
		})
		if err != nil {
			return nil, err
		}
		return &user_api.UpdateBasicResponse{
			Code: user_api.UpdateBasicResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}

	dao.CacheDao.SetSession(ctx, &dao.SessionDbItem{
		SessionId:   sessItem.SessionId,
		UserId:      sessItem.UserId,
		UserName:    sessItem.UserName,
		DisplayName: req.BasicInfo.DisplayName,
		LogoUri:     req.BasicInfo.LogoUri,
	})

	return ret.(*user_api.UpdateBasicResponse), nil
}

func (apiImpl *UserApiImpl) ChangePasswd(ctx context.Context, req *user_api.ChangePasswdRequest) (*user_api.ChangePasswdResponse, error) {
	sessItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_api.ChangePasswdResponse{
			Code:   user_api.ChangePasswdResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err := user_dao.UserPasswdDao.ChangePasswd(sessCtx, sessItem.UserId, req.OldPasswd, req.NewPasswd)
		if err != nil {
			return &user_api.ChangePasswdResponse{
				Code:   user_api.ChangePasswdResponse_CODE_WRONG_OLD_PASSWD,
				ErrMsg: "原密码错误",
			}, nil
		}
		return &user_api.ChangePasswdResponse{
			Code: user_api.ChangePasswdResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*user_api.ChangePasswdResponse), nil
}

func (apiImpl *UserApiImpl) KeepAlive(ctx context.Context, req *user_api.KeepAliveRequest) (*user_api.KeepAliveResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &user_api.KeepAliveResponse{
			Code:   user_api.KeepAliveResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}

	dao.CacheDao.KeepSessionAlive(ctx, req.SessionId, sessionItem.UserId)
	return &user_api.KeepAliveResponse{
		Code: user_api.KeepAliveResponse_CODE_OK,
	}, nil
}

func (apiImpl *UserApiImpl) Register(ctx context.Context, req *user_api.RegisterRequest) (*user_api.RegisterResponse, error) {
	req.UserName = strings.Trim(req.UserName, " \t\r\n")
	if !apiImpl.userCfg.CanRegister {
		return &user_api.RegisterResponse{
			Code:   user_api.RegisterResponse_CODE_NOT_ALLOW,
			ErrMsg: "未开放注册功能",
		}, nil
	}
	if len(req.Passwd) < 6 {
		return &user_api.RegisterResponse{
			Code:   user_api.RegisterResponse_CODE_NOT_ALLOW,
			ErrMsg: "密码长度至少6位",
		}, nil
	}
	if !apiImpl.userCfg.QuickRegister {
		return &user_api.RegisterResponse{
			Code:   user_api.RegisterResponse_CODE_WRONG_REG_CODE,
			ErrMsg: "注册码错误",
		}, nil
	}
	exist, err := user_dao.UserInfoDao.ExistByName(ctx, req.UserName)
	if err != nil {
		return nil, err
	}
	if exist {
		return &user_api.RegisterResponse{
			Code:   user_api.RegisterResponse_CODE_USER_EXIST,
			ErrMsg: "账号已存在",
		}, nil
	}

	if apiImpl.userCfg.QuickRegister {
		if len(req.UserName) < 6 {
			return &user_api.RegisterResponse{
				Code:   user_api.RegisterResponse_CODE_NOT_ALLOW,
				ErrMsg: "用户名长度至少6位",
			}, nil
		}
		match, _ := regexp.MatchString(`^\d+$`, req.UserName)
		if match {
			return &user_api.RegisterResponse{
				Code:   user_api.RegisterResponse_CODE_NOT_ALLOW,
				ErrMsg: "不能使用纯数字账号",
			}, nil
		}
		match, _ = regexp.MatchString(`^[0-9a-zA-Z]+$`, req.UserName)
		if !match {
			return &user_api.RegisterResponse{
				Code:   user_api.RegisterResponse_CODE_NOT_ALLOW,
				ErrMsg: "账号名只支持字母或数字",
			}, nil
		}
	}

	userId := uuid.NewString()
	nowTime := time.Now().UnixMilli()

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		userInfo := &user_dao.UserInfoDbItem{
			UserId:   userId,
			UserName: req.UserName,
			BasicInfo: user_dao.BasicUserInfoDbItem{
				DisplayName: req.BasicInfo.DisplayName,
				LogoUri:     req.BasicInfo.LogoUri,
			},
			CreateTime: nowTime,
			UpdateTime: nowTime,
			UserState:  user_api.USER_STATE_USER_STATE_NORMAL,
		}
		err = api_common.CreateUser(sessCtx, userInfo, req.Passwd)
		if err != nil {
			return nil, err
		}
		return &user_api.RegisterResponse{
			Code: user_api.RegisterResponse_CODE_OK,
		}, nil
	})

	if err != nil {
		return nil, err
	}
	return ret.(*user_api.RegisterResponse), nil
}
